/*
 * Node.h
 *
 *  Created on: Jun 19, 2013
 *      Author: dsweeney
 */

#ifndef NODE_H_
#define NODE_H_


#include "DLStypes.h"
#include <string.h>
#include <iostream>
#include <sstream>
#include <string>

class Node
{
private:
	static unsigned int numNodeId;
	unsigned int nodeId;
	action_t* actions;
	unsigned int numActions;
	unsigned int indexLastAction;
	unsigned int indexLastNode;
	bool fullyExplored;
	unsigned int myX;
	unsigned int myY;
	bool** state;
	unsigned int whenToStopPrintingState;

	action_e parentAction;
public:
///////////////////////////////////////////////////////////////////////////////
	Node (action_e parentAction, bool* state[], int xLocation, int yLocation):
	indexLastAction(0),
	indexLastNode(0),
	fullyExplored(false),
	whenToStopPrintingState(100)
	{
		this->nodeId = this->numNodeId++;

		this->myX = xLocation;
		this->myY = yLocation;

		this->copyState(state);
		this->parentAction = parentAction;

		this->actions = new action_t[NUM_ACTIONS];
		this->numActions = NUM_ACTIONS;

		this->actions[0].actionName = SUCK;
		this->actions[0].cost = 1;

		this->actions[1].actionName = NORTH;
		this->actions[1].cost = 1;

		this->actions[2].actionName = EAST;
		this->actions[2].cost = 1;

		this->actions[3].actionName = SOUTH;
		this->actions[3].cost = 1;

		this->actions[4].actionName = WEST;
		this->actions[4].cost = 1;

		this->applyAction();

		if(whenToStopPrintingState >= this->nodeId)
			this->printState();
	}
///////////////////////////////////////////////////////////////////////////////
	~Node()
	{
		delete [] actions;

		for(unsigned int i = 0; i < x; i++)
		{
			delete [] this->state[i];
		}
		delete[] this->state;
	}
///////////////////////////////////////////////////////////////////////////////
	void expand ()
	{
		for(int i = 0; i < NUM_ACTIONS; i++)
		{
			this->actions[i].child = new Node(this->actions[i].actionName,
					this->state,
					this->myX,
					this->myY);
		}
	}
///////////////////////////////////////////////////////////////////////////////
	Node* getNextChild()
	{
		Node* returnVal = NULL;

		if(this->indexLastNode < NUM_ACTIONS)
		{
			this->actions[indexLastNode].child =
					new Node(this->actions[indexLastNode].actionName,
							this->state,
							this->myX,
							this->myY);
			returnVal = (Node*)this->actions[indexLastNode].child;
			this->indexLastNode++;
		}

		return returnVal;
	}
///////////////////////////////////////////////////////////////////////////////
	action_e getNextAction ()
	{
		action_e returnVal = INVALID;

		if(this->indexLastAction < NUM_ACTIONS)
		{
			returnVal = this->actions[this->indexLastAction].actionName;
			this->indexLastAction++;
		}
		else
			this->fullyExplored = true;

		return returnVal;
	}
///////////////////////////////////////////////////////////////////////////////
	void copyState(bool* sourceState[])
	{
		this->state = new bool* [x];

		for(unsigned int i = 0; i < y; i++)
			this->state[i] = new bool[y];

		for(unsigned int i = 0; i < x; i++)
		{
			for(unsigned int j = 0; j < y; j++)
			{
				this->state[i][j] = sourceState[i][j];
			}
		}
	}
///////////////////////////////////////////////////////////////////////////////
	bool** getState ()
	{
		return (this->state);
	}
///////////////////////////////////////////////////////////////////////////////
	void applyAction()
	{
		std::ostringstream os;
		os<<"nodeId = "<<this->nodeId<<" ";

		switch(this->parentAction)
		{
		case INITIAL_STATE:
			os<<"Location = INITIAL_STATE"<<std::endl;
			break;
		case SUCK:
			this->state[this->myX][this->myY] = CLEAN;
			os<<"Location = ("<<myX<<", "<<myY<<") "<<"ACTION = SUCK"<<std::endl;
			break;
		case NORTH:
			if(this->myX > 0)
				this->myX--;
			os<<"Location = ("<<myX<<", "<<myY<<") "<<"ACTION = NORTH"<<std::endl;
			break;
		case WEST:
			if(this->myY > 0)
				this->myY--;
			os<<"Location = ("<<myX<<", "<<myY<<") "<<"ACTION = EAST"<<std::endl;
			break;
		case SOUTH:
			if(this->myX < (x-1))
				this->myX++;
			os<<"Location = ("<<myX<<", "<<myY<<") "<<"ACTION = SOUTH"<<std::endl;
			break;
		case EAST:
			if(this->myY < (y-1))
				this->myY++;
			os<<"Location = ("<<myX<<", "<<myY<<") "<<"ACTION = WEST"<<std::endl;
			break;
		default:
			std::cout<<"****invalid action****"<<std::endl;
		}
		this->managedPrint(os.str());
	}
///////////////////////////////////////////////////////////////////////////////
	void printState()
	{
		for(unsigned int i = 0; i < x; i++)
		{
			for(unsigned int j = 0; j < y; j++)
			{
				std::cout<<" ("<<i<<", "<<j<<") = "<<(state[i][j])<<std::endl;
			}
		}
	}
///////////////////////////////////////////////////////////////////////////////
	action_e getAction()
	{
		return this->parentAction;
	}
///////////////////////////////////////////////////////////////////////////////
	unsigned int getId()
	{
		return this->nodeId;
	}
///////////////////////////////////////////////////////////////////////////////
	void managedPrint(std::string os)
	{
		if(this->nodeId <= 100)
			std::cout<<os;
	}
};

unsigned int Node::numNodeId = 0;


#endif /* NODE_H_ */
